﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace XGameFrame
{
    public abstract class MapBase
    {
        #region Innerclass Region
        #region MapRow
        public class MapRow
        {
            public List<FieldCell> Column = new List<FieldCell>();
        }
        #endregion

        #endregion

        #region EnumRegion
        public enum MapType
        {
            TileMap = 0,
            HexagonalMap = 1,
            IsometricTileMap = 2,
            IsometricHexagonalMap = 3
        };
        #endregion

        #region Field Region
        private int mapWidth;
        private int mapHeight;
        private List<MapRow> row;
        private TileHandler tileHandler;

        private const float HEIGHT_DEPHT_MOD = 0.0000001f;
        private float maxDepht;
        private float dephtOffset;

        private MapCamera camera;
        #endregion

        #region Property Region
        /// <summary>
        /// Get widht of a map in tiles or set it
        /// </summary>
        public int MapWidth
        {
            get { return mapWidth; }
            set { mapWidth = value; }
        }

        /// <summary>
        /// Get height of a map in tiles or set it
        /// </summary>
        public int MapHeight
        {
            get { return mapHeight; }
            set { mapHeight = value; }
        }

        /// <summary>
        /// Get maxdepht of a map or set it
        /// </summary>
        public float MaxDepht
        {
            get { return maxDepht; }
            set { maxDepht = value; }
        }

        /// <summary>
        /// Get offset from dephtt of a map or set it
        /// </summary>
        public float DephtOffset
        {
            get { return dephtOffset; }
            set { dephtOffset = value; }
        }

        /// <summary>
        /// Get a row of the map or set it
        /// </summary>
        public List<MapRow> Row
        {
            get { return row; }
            set { row = value; }
        }

        /// <summary>
        /// Get the tilehandler of these map or set it
        /// </summary>
        public TileHandler TileHandler
        {
            get { return tileHandler; }
            set { tileHandler = value; }
        }

        /// <summary>
        /// Get the maps camera or set it
        /// </summary>
        public MapCamera Camera
        {
            get { return camera; }
            set { camera = value; }
        }
        #endregion

        /// <summary>
        /// Creates a new MapBase
        /// </summary>
        /// <param name="pTileHandler">TileHandler which is to use</param>
        /// <param name="pMapWidht">Optional map widht</param>
        /// <param name="pMapHeight">Optional map height</param>
        public MapBase(TileHandler pTileHandler, int pMapWidht = 50, int pMapHeight = 50)
        {
            MapWidth = pMapWidht;
            MapHeight = pMapHeight;
            TileHandler = pTileHandler;

            MaxDepht = ((MapWidth + 1) + ((MapHeight + 1) * TileHandler.TileSize.Y)) * 10;

            Camera = new MapCamera(this);
            Row = new List<MapRow>();
            GenerateMap(MapWidth, MapHeight);
        }

        #region Abstract Methods
        /// <summary>
        /// Do Logic for AnimatedSprites
        /// </summary>
        public virtual void Update(GameTime pGameTime)
        {

        }

        /// <summary>
        /// Do drawings for AnimatedSprites
        /// </summary>
        /// <param name="pSpriteBatch">The graphic to draw</param>
        public virtual void Draw(SpriteBatch pSpriteBatch)
        {
            pSpriteBatch.Begin(SpriteSortMode.BackToFront, BlendState.AlphaBlend);
            //Atm normal mode to draw a map...maybe has to change for better extending
            for(int y = 0 ; y < this.MapHeight ; y++)
            {
                int rowOffset = 0;
                if(y % 2 == 1)
                    rowOffset = this.TileHandler.XOffset;

                for(int x = 0 ; x < this.MapWidth ; x++)
                {
                    DephtOffset = 0.7f - ((x + (y * TileHandler.TileSize.X)) / MaxDepht);

                    foreach(int _fieldID in this.Row[y].Column[x].GroundFields)
                    {
                        pSpriteBatch.Draw(TileHandler.TileSet,
                                          new Rectangle(
                                                        (x * (int)TileHandler.TileStep.X) - 0 + rowOffset + (int)TileHandler.PosiitionCorrection.X,
                                                        (y * (int)TileHandler.TileStep.Y) - 0 + (int)TileHandler.PosiitionCorrection.Y,
                                                        (int)TileHandler.TileSize.X,
                                                        (int)TileHandler.TileSize.Y),
                                          TileHandler.GetSourceTileRectangle(_fieldID),
                                          Color.White,
                                          0.0f,
                                          Vector2.Zero,
                                          SpriteEffects.None,
                                          1.0f);
                    }

                    int objectLevel = 0;
                    foreach(int _fieldID in this.Row[y].Column[x].HeightFields)
                    {
                        pSpriteBatch.Draw(TileHandler.TileSet,
                                          new Rectangle(
                                                        (x * (int)TileHandler.TileStep.X) - 0 + rowOffset + (int)TileHandler.PosiitionCorrection.X,
                                                        (y * (int)TileHandler.TileStep.Y) - 0 + (int)TileHandler.PosiitionCorrection.Y - (objectLevel * TileHandler.HeightOffset),
                                                        (int)TileHandler.TileSize.X,
                                                        (int)TileHandler.TileSize.Y),
                                          TileHandler.GetSourceTileRectangle(_fieldID),
                                          Color.White,
                                          0.0f,
                                          Vector2.Zero,
                                          SpriteEffects.None,
                                          DephtOffset - ((float)objectLevel * HEIGHT_DEPHT_MOD));
                        objectLevel++;
                    }

                    foreach(int _fieldID in this.Row[y].Column[x].OverlayFields)
                    {
                        pSpriteBatch.Draw(TileHandler.TileSet,
                                          new Rectangle(
                                                        (x * (int)TileHandler.TileStep.X) - 0 + rowOffset + (int)TileHandler.PosiitionCorrection.X,
                                                        (y * (int)TileHandler.TileStep.Y) - 0 + (int)TileHandler.PosiitionCorrection.Y - (objectLevel * TileHandler.HeightOffset),
                                                        (int)TileHandler.TileSize.X,
                                                        (int)TileHandler.TileSize.Y),
                                          TileHandler.GetSourceTileRectangle(_fieldID),
                                          Color.White,
                                          0.0f,
                                          Vector2.Zero,
                                          SpriteEffects.None,
                                          DephtOffset - ((float)objectLevel * HEIGHT_DEPHT_MOD));
                    }
                }
            }

            pSpriteBatch.End();
        }
        /// <summary>
        /// Do logic if the element is Hover
        /// </summary>
        /// <param name="pPlayerIndex">normally the player how has hoverd the element</param>
        public abstract void OnHover(PlayerIndex pPlayerIndex);

        public abstract void HandleInput(PlayerIndex pPlayerIndex);

        #endregion

        #region Method Region
        private void GenerateMap(int pMapWidht, int pMapHeight)
        {
            for(int _heightPosition = 0 ; _heightPosition < pMapWidht ; _heightPosition++)
            {
                MapRow tmpRow = new MapRow();
                for(int _widhtPosition = 0 ; _widhtPosition < pMapWidht ; _widhtPosition++)
                {
                    tmpRow.Column.Add(new FieldCell());
                }
                Row.Add(tmpRow);
            }

            //Add logic for mapgeneration here

            //for example : 
            //Row[coordY].Column[coordX].AddMultipleFieldIDs(tile,tile1,tile2...tileN);  ** for fields with some layers **
            //or 
            //Row[coordY].Column[coordX].FieldID = tile;  ** for a normal field **
        }
        #endregion
    }
}
